﻿////***************************************************************************************
//// LitWavesApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
////
//// Use arrow keys to move light positions.
////
////***************************************************************************************
//
//#include "../../Common/d3dApp.h"
//#include "../../Common/MathHelper.h"
//#include "../../Common/UploadBuffer.h"
//#include "../../Common/GeometryGenerator.h"
//#include "FrameResourceWaves.h"
//#include "LitWaves.h"
//
//using Microsoft::WRL::ComPtr;
//using namespace DirectX;
//using namespace DirectX::PackedVector;
//
//#pragma comment(lib, "d3dcompiler.lib")
//#pragma comment(lib, "D3D12.lib")
//
//const int gNumFrameResources = 3;
//
//// Lightweight structure stores parameters to draw a shape.  This will
//// vary from app-to-app.
//struct RenderItem
//{
//	RenderItem() = default;
//
//	// World matrix of the shape that describes the object's local space
//	// relative to the world space, which defines the position, orientation,
//	// and scale of the object in the world.
//	XMFLOAT4X4 World = MathHelper::Identity4x4();
//
//	XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
//
//	// Dirty flag indicating the object data has changed and we need to update the constant buffer.
//	// Because we have an object cbuffer for each FrameResourceWaves, we have to apply the
//	// update to each FrameResourceWaves.  Thus, when we modify obect data we should set 
//	// NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
//	int NumFramesDirty = gNumFrameResources;
//
//	// Index into GPU constant buffer corresponding to the ObjectCB for this render item.
//	UINT ObjCBIndex = -1;
//
//	Material* Mat = nullptr;
//	MeshGeometry* Geo = nullptr;
//
//	// Primitive topology.
//	D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
//
//	// DrawIndexedInstanced parameters.
//	UINT IndexCount = 0;
//	UINT StartIndexLocation = 0;
//	int BaseVertexLocation = 0;
//};
//
//enum class RenderLayer : int
//{
//	Opaque = 0,
//	Count
//};
//
//class LitWavesApp : public D3DApp
//{
//public:
//    LitWavesApp(HINSTANCE hInstance);
//    LitWavesApp(const LitWavesApp& rhs) = delete;
//    LitWavesApp& operator=(const LitWavesApp& rhs) = delete;
//    ~LitWavesApp();
//
//    virtual bool Initialize()override;
//
//private:
//    virtual void OnResize()override;
//    virtual void Update(const GameTimer& gt)override;
//    virtual void Draw(const GameTimer& gt)override;
//
//    virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
//    virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
//    virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
//
//	void OnKeyboardInput(const GameTimer& gt);
//	void UpdateCamera(const GameTimer& gt);
//	void UpdateObjectCBs(const GameTimer& gt);
//	void UpdateMaterialCBs(const GameTimer& gt);
//	void UpdateMainPassCB(const GameTimer& gt);
//	void UpdateWaves(const GameTimer& gt);
//
//    void BuildRootSignature();
//    void BuildShadersAndInputLayout();
//    void BuildLandGeometry();
//    void BuildWavesGeometryBuffers();
//    void BuildPSOs();
//    void BuildFrameResources();
//    void BuildMaterials();
//    void BuildRenderItems();
//	void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
//
//    float GetHillsHeight(float x, float z)const;
//    XMFLOAT3 GetHillsNormal(float x, float z)const;
//
//private:
//
//    std::vector<std::unique_ptr<FrameResourceWaves>> mFrameResources;
//    FrameResourceWaves* mCurrFrameResource = nullptr;
//    int mCurrFrameResourceIndex = 0;
//
//    UINT mCbvSrvDescriptorSize = 0;
//
//    ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
//
//	std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
//	std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
//	std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
//	std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
//	std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
//
//	std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
//
//	RenderItem* mWavesRitem = nullptr;
//
//	// List of all the render items.
//	std::vector<std::unique_ptr<RenderItem>> mAllRitems;
//
//	// Render items divided by PSO.
//	std::vector<RenderItem*> mRitemLayer[(int)RenderLayer::Count];
//
//	std::unique_ptr<LitWaves> mWaves;
//
//    PassConstants mMainPassCB;
//
//	XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
//	XMFLOAT4X4 mView = MathHelper::Identity4x4();
//	XMFLOAT4X4 mProj = MathHelper::Identity4x4();
//
//    float mTheta = 1.5f*XM_PI;
//    float mPhi = XM_PIDIV2 - 0.1f;
//    float mRadius = 50.0f;
//
//	float mSunTheta = 1.25f*XM_PI;
//	float mSunPhi = XM_PIDIV4;
//
//    POINT mLastMousePos;
//};
//
//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
//    PSTR cmdLine, int showCmd)
//{
//    // Enable run-time memory check for debug builds.
//#if defined(DEBUG) | defined(_DEBUG)
//    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
//#endif
//
//    try
//    {
//        LitWavesApp theApp(hInstance);
//        if(!theApp.Initialize())
//            return 0;
//
//        return theApp.Run();
//    }
//    catch(DxException& e)
//    {
//        MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
//        return 0;
//    }
//}
//
//LitWavesApp::LitWavesApp(HINSTANCE hInstance)
//    : D3DApp(hInstance)
//{
//}
//
//LitWavesApp::~LitWavesApp()
//{
//    if(md3dDevice != nullptr)
//        FlushCommandQueue();
//}
//
//bool LitWavesApp::Initialize()
//{
//    if(!D3DApp::Initialize())
//        return false;
//
//    // Reset the command list to prep for initialization commands.
//    ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
//
//    // Get the increment size of a descriptor in this heap type.  This is hardware specific, so we have
//    // to query this information.
//    mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
//
//	mWaves = std::make_unique<LitWaves>(128, 128, 1.0f, 0.03f, 4.0f, 0.2f);
//
//    BuildRootSignature();
//    BuildShadersAndInputLayout();
//	BuildLandGeometry();
//    BuildWavesGeometryBuffers();
//	BuildMaterials();
//    BuildRenderItems();
//	BuildRenderItems();
//    BuildFrameResources();
//	BuildPSOs();
//
//    // Execute the initialization commands.
//    ThrowIfFailed(mCommandList->Close());
//    ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
//    mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
//
//    // Wait until initialization is complete.
//    FlushCommandQueue();
//
//    return true;
//}
// 
//void LitWavesApp::OnResize()
//{
//    D3DApp::OnResize();
//
//    // The window resized, so update the aspect ratio and recompute the projection matrix.
//    XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
//    XMStoreFloat4x4(&mProj, P);
//}
//
//void LitWavesApp::Update(const GameTimer& gt)
//{
//	OnKeyboardInput(gt);
//	UpdateCamera(gt);
//
//	// Cycle through the circular frame resource array.
//	mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
//	mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
//
//	// Has the GPU finished processing the commands of the current frame resource?
//	// If not, wait until the GPU has completed commands up to this fence point.
//	if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
//	{
//		HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
//		ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
//		WaitForSingleObject(eventHandle, INFINITE);
//		CloseHandle(eventHandle);
//	}
//
//	UpdateObjectCBs(gt);
//	UpdateMaterialCBs(gt);
//	UpdateMainPassCB(gt);
//	UpdateWaves(gt);
//}
//
//void LitWavesApp::Draw(const GameTimer& gt)
//{
//	auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
//
//	// Reuse the memory associated with command recording.
//	// We can only reset when the associated command lists have finished execution on the GPU.
//	ThrowIfFailed(cmdListAlloc->Reset());
//
//	// A command list can be reset after it has been added to the command queue via ExecuteCommandList.
//	// Reusing the command list reuses memory.
//	ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
//
//	mCommandList->RSSetViewports(1, &mScreenViewport);
//	mCommandList->RSSetScissorRects(1, &mScissorRect);
//
//	// Indicate a state transition on the resource usage.
//	mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
//		D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
//
//	// Clear the back buffer and depth buffer.
//	mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
//	mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
//
//	// Specify the buffers we are going to render to.
//	mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
//
//	mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
//
//	auto passCB = mCurrFrameResource->PassCB->Resource();
//	mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
//
//	DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);
//
//	// Indicate a state transition on the resource usage.
//	mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
//		D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
//
//	// Done recording commands.
//	ThrowIfFailed(mCommandList->Close());
//
//	// Add the command list to the queue for execution.
//	ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
//	mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
//
//	// Swap the back and front buffers
//	ThrowIfFailed(mSwapChain->Present(0, 0));
//	mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
//
//	// Advance the fence value to mark commands up to this fence point.
//	mCurrFrameResource->Fence = ++mCurrentFence;
//
//	// Add an instruction to the command queue to set a new fence point. 
//    // Because we are on the GPU timeline, the new fence point won't be 
//    // set until the GPU finishes processing all the commands prior to this Signal().
//	mCommandQueue->Signal(mFence.Get(), mCurrentFence);
//}
//
//void LitWavesApp::OnMouseDown(WPARAM btnState, int x, int y)
//{
//    mLastMousePos.x = x;
//    mLastMousePos.y = y;
//
//    SetCapture(mhMainWnd);
//}
//
//void LitWavesApp::OnMouseUp(WPARAM btnState, int x, int y)
//{
//    ReleaseCapture();
//}
//
//void LitWavesApp::OnMouseMove(WPARAM btnState, int x, int y)
//{
//    if((btnState & MK_LBUTTON) != 0)
//    {
//        // Make each pixel correspond to a quarter of a degree.
//        float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
//        float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
//
//        // Update angles based on input to orbit camera around box.
//        mTheta += dx;
//        mPhi += dy;
//
//        // Restrict the angle mPhi.
//        mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
//    }
//    else if((btnState & MK_RBUTTON) != 0)
//    {
//        // Make each pixel correspond to 0.2 unit in the scene.
//        float dx = 0.2f*static_cast<float>(x - mLastMousePos.x);
//        float dy = 0.2f*static_cast<float>(y - mLastMousePos.y);
//
//        // Update the camera radius based on input.
//        mRadius += dx - dy;
//
//        // Restrict the radius.
//        mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
//    }
//
//    mLastMousePos.x = x;
//    mLastMousePos.y = y;
//}
//
//void LitWavesApp::OnKeyboardInput(const GameTimer& gt)
//{
//	const float dt = gt.DeltaTime();
//
//	if(GetAsyncKeyState(VK_LEFT) & 0x8000)
//		mSunTheta -= 1.0f*dt;
//
//	if(GetAsyncKeyState(VK_RIGHT) & 0x8000)
//		mSunTheta += 1.0f*dt;
//
//	if(GetAsyncKeyState(VK_UP) & 0x8000)
//		mSunPhi -= 1.0f*dt;
//
//	if(GetAsyncKeyState(VK_DOWN) & 0x8000)
//		mSunPhi += 1.0f*dt;
//
//	mSunPhi = MathHelper::Clamp(mSunPhi, 0.1f, XM_PIDIV2);
//}
//
//void LitWavesApp::UpdateCamera(const GameTimer& gt)
//{
//	// Convert Spherical to Cartesian coordinates.
//	mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
//	mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
//	mEyePos.y = mRadius*cosf(mPhi);
//
//	// Build the view matrix.
//	XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
//	XMVECTOR target = XMVectorZero();
//	XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
//
//	XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
//	XMStoreFloat4x4(&mView, view);
//}
//
//void LitWavesApp::UpdateObjectCBs(const GameTimer& gt)
//{
//	auto currObjectCB = mCurrFrameResource->ObjectCB.get();
//	for(auto& e : mAllRitems)
//	{
//		// Only update the cbuffer data if the constants have changed.  
//		// This needs to be tracked per frame resource.
//		if(e->NumFramesDirty > 0)
//		{
//			XMMATRIX world = XMLoadFloat4x4(&e->World);
//			XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
//
//			ObjectConstants objConstants;
//			XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
//
//			currObjectCB->CopyData(e->ObjCBIndex, objConstants);
//
//			// Next FrameResourceWaves need to be updated too.
//			e->NumFramesDirty--;
//		}
//	}
//}
//
//void LitWavesApp::UpdateMaterialCBs(const GameTimer& gt)
//{
//	auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
//	for(auto& e : mMaterials)
//	{
//		// Only update the cbuffer data if the constants have changed.  If the cbuffer
//		// data changes, it needs to be updated for each FrameResourceWaves.
//      // 如果材质常量数据有了变化就更新常量缓冲区数据。一旦常量缓冲区数据发生改变，就需对每一个帧
//      // 资源FrameResource进行更新
//		Material* mat = e.second.get();
//		if(mat->NumFramesDirty > 0)
//		{
//			XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
//
//			MaterialConstants matConstants;
//			matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
//			matConstants.FresnelR0 = mat->FresnelR0;
//			matConstants.Roughness = mat->Roughness;
//
//			currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
//
//			// Next FrameResourceWaves need to be updated too.
//          // 也需要对下一个FrameResource进行更新
//			mat->NumFramesDirty--;
//		}
//	}
//}
//
//void LitWavesApp::UpdateMainPassCB(const GameTimer& gt)
//{
//	XMMATRIX view = XMLoadFloat4x4(&mView);
//	XMMATRIX proj = XMLoadFloat4x4(&mProj);
//
//	XMMATRIX viewProj = XMMatrixMultiply(view, proj);
//	XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
//	XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
//	XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
//
//	XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
//	XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
//	XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
//	XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
//	XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
//	XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
//	mMainPassCB.EyePosW = mEyePos;
//	mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
//	mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
//	mMainPassCB.NearZ = 1.0f;
//	mMainPassCB.FarZ = 1000.0f;
//	mMainPassCB.TotalTime = gt.TotalTime();
//	mMainPassCB.DeltaTime = gt.DeltaTime();
//	mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
//
//	XMVECTOR lightDir = -MathHelper::SphericalToCartesian(1.0f, mSunTheta, mSunPhi);
//
//	XMStoreFloat3(&mMainPassCB.Lights[0].Direction, lightDir);
//	mMainPassCB.Lights[0].Strength = { 1.0f, 1.0f, 0.9f };
//
//	auto currPassCB = mCurrFrameResource->PassCB.get();
//	currPassCB->CopyData(0, mMainPassCB);
//}
//
//void LitWavesApp::UpdateWaves(const GameTimer& gt)
//{
//	// Every quarter second, generate a random wave.
//	static float t_base = 0.0f;
//	if((mTimer.TotalTime() - t_base) >= 0.25f)
//	{
//		t_base += 0.25f;
//
//		int i = MathHelper::Rand(4, mWaves->RowCount() - 5);
//		int j = MathHelper::Rand(4, mWaves->ColumnCount() - 5);
//
//		float r = MathHelper::RandF(0.2f, 0.5f);
//
//		mWaves->Disturb(i, j, r);
//	}
//
//	// Update the wave simulation.
//	mWaves->Update(gt.DeltaTime());
//
//	// Update the wave vertex buffer with the new solution.
//	auto currWavesVB = mCurrFrameResource->WavesVB.get();
//	for(int i = 0; i < mWaves->VertexCount(); ++i)
//	{
//		Vertex v;
//
//		v.Pos = mWaves->Position(i);
//		v.Normal = mWaves->Normal(i);
//
//		currWavesVB->CopyData(i, v);
//	}
//
//	// Set the dynamic VB of the wave renderitem to the current frame VB.
//	mWavesRitem->Geo->VertexBufferGPU = currWavesVB->Resource();
//}
//
//void LitWavesApp::BuildRootSignature()
//{
//    // Root parameter can be a table, root descriptor or root constants.
//    CD3DX12_ROOT_PARAMETER slotRootParameter[3];
//
//    // Create root CBV.
//    slotRootParameter[0].InitAsConstantBufferView(0);
//    slotRootParameter[1].InitAsConstantBufferView(1);
//    slotRootParameter[2].InitAsConstantBufferView(2);
//
//    // A root signature is an array of root parameters.
//	CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(3, slotRootParameter, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
//
//    // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
//    ComPtr<ID3DBlob> serializedRootSig = nullptr;
//    ComPtr<ID3DBlob> errorBlob = nullptr;
//    HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
//        serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
//
//    if(errorBlob != nullptr)
//    {
//        ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
//    }
//    ThrowIfFailed(hr);
//
//    ThrowIfFailed(md3dDevice->CreateRootSignature(
//		0,
//        serializedRootSig->GetBufferPointer(),
//        serializedRootSig->GetBufferSize(),
//        IID_PPV_ARGS(mRootSignature.GetAddressOf())));
//}
//
//void LitWavesApp::BuildShadersAndInputLayout()
//{
//	mShaders["standardVS"] = d3dUtil::CompileShader(L"E:\\DX12Book\\DX12LearnProject\\DX12Learn\\LearnDemo\\LitWaves\\Shaders\\Default.hlsl", nullptr, "VS", "vs_5_0");
//	mShaders["opaquePS"] = d3dUtil::CompileShader(L"E:\\DX12Book\\DX12LearnProject\\DX12Learn\\LearnDemo\\LitWaves\\Shaders\\Default.hlsl", nullptr, "PS", "ps_5_0");
//
//    mInputLayout =
//    {
//        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
//        { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
//    };
//}
//
//void LitWavesApp::BuildLandGeometry()
//{
//	GeometryGenerator geoGen;
//	GeometryGenerator::MeshData grid = geoGen.CreateGrid(160.0f, 160.0f, 50, 50);
//
//	//
//	// Extract the vertex elements we are interested and apply the height function to
//	// each vertex.  In addition, color the vertices based on their height so we have
//	// sandy looking beaches, grassy low hills, and snow mountain peaks.
//	//
//
//	std::vector<Vertex> vertices(grid.Vertices.size());
//	for(size_t i = 0; i < grid.Vertices.size(); ++i)
//	{
//		auto& p = grid.Vertices[i].Position;
//		vertices[i].Pos = p;
//		vertices[i].Pos.y = GetHillsHeight(p.x, p.z);
//		vertices[i].Normal = GetHillsNormal(p.x, p.z);
//	}
//
//	const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
//
//	std::vector<std::uint16_t> indices = grid.GetIndices16();
//	const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
//
//	auto geo = std::make_unique<MeshGeometry>();
//	geo->Name = "landGeo";
//
//	ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
//	CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
//
//	ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
//	CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
//
//	geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
//		mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
//
//	geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
//		mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
//
//	geo->VertexByteStride = sizeof(Vertex);
//	geo->VertexBufferByteSize = vbByteSize;
//	geo->IndexFormat = DXGI_FORMAT_R16_UINT;
//	geo->IndexBufferByteSize = ibByteSize;
//
//	SubmeshGeometry submesh;
//	submesh.IndexCount = (UINT)indices.size();
//	submesh.StartIndexLocation = 0;
//	submesh.BaseVertexLocation = 0;
//
//	geo->DrawArgs["grid"] = submesh;
//
//	mGeometries["landGeo"] = std::move(geo);
//}
//
//void LitWavesApp::BuildWavesGeometryBuffers()
//{
//	std::vector<std::uint16_t> indices(3 * mWaves->TriangleCount()); // 3 indices per face
//	assert(mWaves->VertexCount() < 0x0000ffff);
//
//	// Iterate over each quad.
//	int m = mWaves->RowCount();
//	int n = mWaves->ColumnCount();
//	int k = 0;
//	for(int i = 0; i < m - 1; ++i)
//	{
//		for(int j = 0; j < n - 1; ++j)
//		{
//			indices[k] = i*n + j;
//			indices[k + 1] = i*n + j + 1;
//			indices[k + 2] = (i + 1)*n + j;
//
//			indices[k + 3] = (i + 1)*n + j;
//			indices[k + 4] = i*n + j + 1;
//			indices[k + 5] = (i + 1)*n + j + 1;
//
//			k += 6; // next quad
//		}
//	}
//
//	UINT vbByteSize = mWaves->VertexCount()*sizeof(Vertex);
//	UINT ibByteSize = (UINT)indices.size()*sizeof(std::uint16_t);
//
//	auto geo = std::make_unique<MeshGeometry>();
//	geo->Name = "waterGeo";
//
//	// Set dynamically.
//	geo->VertexBufferCPU = nullptr;
//	geo->VertexBufferGPU = nullptr;
//
//	ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
//	CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
//
//	geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
//		mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
//
//	geo->VertexByteStride = sizeof(Vertex);
//	geo->VertexBufferByteSize = vbByteSize;
//	geo->IndexFormat = DXGI_FORMAT_R16_UINT;
//	geo->IndexBufferByteSize = ibByteSize;
//
//	SubmeshGeometry submesh;
//	submesh.IndexCount = (UINT)indices.size();
//	submesh.StartIndexLocation = 0;
//	submesh.BaseVertexLocation = 0;
//
//	geo->DrawArgs["grid"] = submesh;
//
//	mGeometries["waterGeo"] = std::move(geo);
//}
//
//void LitWavesApp::BuildPSOs()
//{
//	D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
//
//	//
//	// PSO for opaque objects.
//	//
//	ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
//	opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
//	opaquePsoDesc.pRootSignature = mRootSignature.Get();
//	opaquePsoDesc.VS =
//	{
//		reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()),
//		mShaders["standardVS"]->GetBufferSize()
//	};
//	opaquePsoDesc.PS =
//	{
//		reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
//		mShaders["opaquePS"]->GetBufferSize()
//	};
//	opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
//	opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
//	opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
//	opaquePsoDesc.SampleMask = UINT_MAX;
//	opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
//	opaquePsoDesc.NumRenderTargets = 1;
//	opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
//	opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
//	opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
//	opaquePsoDesc.DSVFormat = mDepthStencilFormat;
//	ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
//}
//
//void LitWavesApp::BuildFrameResources()
//{
//    for(int i = 0; i < gNumFrameResources; ++i)
//    {
//        mFrameResources.push_back(std::make_unique<FrameResourceWaves>(md3dDevice.Get(),
//            1, (UINT)mAllRitems.size(), (UINT)mMaterials.size(), mWaves->VertexCount()));
//    }
//}
//
//void LitWavesApp::BuildMaterials()
//{
//	auto grass = std::make_unique<Material>();
//	grass->Name = "grass";
//	grass->MatCBIndex = 0;
//    grass->DiffuseAlbedo = XMFLOAT4(0.2f, 0.6f, 0.2f, 1.0f);
//    grass->FresnelR0 = XMFLOAT3(0.01f, 0.01f, 0.01f);
//    grass->Roughness = 0.125f;
//
//    // This is not a good water material definition, but we do not have all the rendering
//    // tools we need (transparency, environment reflection), so we fake it for now.
//    // 当前这种水的材质定义得并不是很好，但是由于我们还未学会所需的全部渲染工具（如透明度、环境反
//    // 射等），因此暂时先用这些数据解当务之急吧
//	auto water = std::make_unique<Material>();
//	water->Name = "water";
//	water->MatCBIndex = 1;
//    water->DiffuseAlbedo = XMFLOAT4(0.0f, 0.2f, 0.6f, 1.0f);
//    water->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
//    water->Roughness = 0.0f;
//
//	mMaterials["grass"] = std::move(grass);
//	mMaterials["water"] = std::move(water);
//}
//
//void LitWavesApp::BuildRenderItems()
//{
//	auto wavesRitem = std::make_unique<RenderItem>();
//	wavesRitem->World = MathHelper::Identity4x4();
//	wavesRitem->ObjCBIndex = 0;
//	wavesRitem->Mat = mMaterials["water"].get();
//	wavesRitem->Geo = mGeometries["waterGeo"].get();
//	wavesRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
//	wavesRitem->IndexCount = wavesRitem->Geo->DrawArgs["grid"].IndexCount;
//	wavesRitem->StartIndexLocation = wavesRitem->Geo->DrawArgs["grid"].StartIndexLocation;
//	wavesRitem->BaseVertexLocation = wavesRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
//
//	mWavesRitem = wavesRitem.get();
//
//	mRitemLayer[(int)RenderLayer::Opaque].push_back(wavesRitem.get());
//
//	auto gridRitem = std::make_unique<RenderItem>();
//	gridRitem->World = MathHelper::Identity4x4();
//	gridRitem->ObjCBIndex = 1;
//	gridRitem->Mat = mMaterials["grass"].get();
//	gridRitem->Geo = mGeometries["landGeo"].get();
//	gridRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
//	gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
//	gridRitem->StartIndexLocation = gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
//	gridRitem->BaseVertexLocation = gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
//
//	mRitemLayer[(int)RenderLayer::Opaque].push_back(gridRitem.get());
//
//	mAllRitems.push_back(std::move(wavesRitem));
//	mAllRitems.push_back(std::move(gridRitem));
//}
//
//void LitWavesApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
//{
//	UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
//	UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
//
//	auto objectCB = mCurrFrameResource->ObjectCB->Resource();
//	auto matCB = mCurrFrameResource->MaterialCB->Resource();
//
//	// For each render item...
//	for(size_t i = 0; i < ritems.size(); ++i)
//	{
//		auto ri = ritems[i];
//
//		cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
//		cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
//		cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
//
//		D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
//		D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
//
//		cmdList->SetGraphicsRootConstantBufferView(0, objCBAddress);
//		cmdList->SetGraphicsRootConstantBufferView(1, matCBAddress);
//
//		cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
//	}
//}
//
//float LitWavesApp::GetHillsHeight(float x, float z)const
//{
//    return 0.3f*(z*sinf(0.1f*x) + x*cosf(0.1f*z));
//}
//
///*
//注:叉积公式:
//    设向量a=(ax,ay,az)和b(bx,by,bz)，它们的叉积为:c=(cx,cy,cz)
//    有: cx=ay·bz - az·by   或者矩阵表示:       |i    j    k|
//        cy=az·bx - ax·bz              c=aXb= |ax  ay  az|  其中,i、j、k分别为沿x、y、z轴的单位向量
//        cz=ax·by - ay·bx                     |bx  by  bz|
//
//GeometryGenerator类中用于生成各种几何形状的函数，已能够通过顶点法线去创建对应的图形数据，可谓万事俱备。
//然而，由于我们为了令地形（terrain）表面更加真实而修改了此演示程序中的栅格高度，所以还需为地形生成法向量。
//因为地形曲面由函数[y=f(x,z)]给出，所以我们可以通过微积分知识来直接计算法向量，而不必再用8.2.1节中所述的求法线平均值方法。
//为此，针对曲面上的每一个点，我们都通过偏导数在+x与+z方向上建立两个切向量（tangent vector）：
//// "δ"（delta）: 数学上表示变化量：表示一个变量的变化或增量，如在微积分中δx 表示变量 𝑥x 的一个微小变化。
//T(x) = (1,δf/δx,0)
//T(z) = (1,δf/δz,0)
//这两个向量都位于曲面点的切平面上，求这两个向量的叉积即可得到对应点处的法向量：
//                  |i    j    k|     |δf/δz  1|   |0    1|  |0  δf/δz|
//n = T(x) X T(z) = |0  δf/δz  1| = ( |        |, -|      |, |        | ) = (-δf/δx, 1, -δf/δz)
//                  |1  δf/δx  0|     |δf/δx  0|   |1    0|  |1  δf/δx|
//用来生成陆地网格的函数为：[f(x,z) = 0.3z·sin(0.1x) + 0.3x·cos(0.1z)]
//则偏导数为：[δf/δx = 0.03z·cos(0.1x) + 0.3·cos(0.1z)     δf/δz = 0.3·sin(0.1x) - 0.03x·sin(0.1z)]
//而位于曲面上一点[x,f(x,z),z]处的曲线法线为：
//                           ([  -0.03z·cos(0.1x) - 0.3·cos(0.1z) ]) ^ T
//n(x,z)=(-δf/δx, 1, -δf/δz)=([                1                  ])
//                           ([  -0.3·sin(0.1x) + 0.03x·sin(0.1z) ])
//
//我们可以注意到曲面法线并不具有单位长度，所以在光照计算之前还需对它进行规范化处理。我们要在每个顶点处都进行上述的法线计算，以获取对应的顶点法线：
//*/
//XMFLOAT3 LitWavesApp::GetHillsNormal(float x, float z)const
//{
//    // n = (-df/dx, 1, -df/dz)
//    XMFLOAT3 n(
//        -0.03f*z*cosf(0.1f*x) - 0.3f*cosf(0.1f*z),
//        1.0f,
//        -0.3f*sinf(0.1f*x) + 0.03f*x*sinf(0.1f*z));
//
//    XMVECTOR unitNormal = XMVector3Normalize(XMLoadFloat3(&n));
//    XMStoreFloat3(&n, unitNormal);
//
//    return n;
//}
